package main

type node[E any] struct {
	val E
	next *node[E]
}
type linkedList[E any] struct {
	head *node[E]
	tail *node[E]
	len int
}

func (list *linkedList[E]) add(e E){
	if list.tail == nil {
		list.head = &node[E]{e, nil}
		list.tail = list.head
		list.len++
		return
	}
	list.tail.next = &node[E]{e, nil}
	list.tail = list.tail.next
	list.len++
}

func (list *linkedList[E]) addAll(list2 *linkedList[E]) {
	if list2 != nil {
		for node2 := list2.head; node2 != nil; {
			list.add(node2.val)
			node2 = node2.next
		}
	}
}

func (list *linkedList[E]) show() {
	var tmp *node[E] = list.head
	print("[")
	for tmp != nil {
		print(tmp.val)
		tmp = tmp.next
		if tmp != nil {
			print(" -> ")
		}
	}
	println("]")
}

func (list *linkedList[E]) clear() {
	list.head = nil
	list.tail = nil
	list.len = 0
}

func (list *linkedList[E]) set(i int, e E) {
	if i >= list.len || i < 0 {
		return
	}
	tmp := list.head
	for {
		if i == 0 {
			tmp.val = e
			break
		}
		i--
		tmp = tmp.next
	}
}

func (list *linkedList[E]) remove(i int) *E {
	if i >= list.len || i < 0 {
		return nil
	}
	if i == 0 {
		res := list.head.val
		list.head = list.head.next
		list.len --
		return &res
	}
	for node := list.head;;{
		if i == 1 {
			res := node.next.val
			node.next = node.next.next
			list.len --
			return &res
		}
		i --
		node = node.next
	}
}

func (list *linkedList[E]) pop() *E{
	return list.remove(0)
}

func (list *linkedList[E]) push(e E) {
	list.indexAdd(0, e)
}

func (list *linkedList[E]) indexAdd(i int, e E) {
	if i == 0 && list.len == 0{
		list.add(e)
		return
	}
	if i == 0 {
		anode := &node[E]{e, list.head}
		list.head = anode
		list.len ++
		return
	}
	for tmp := list.head;;{
		if i == 1 {
			nnode := &node[E]{e, tmp.next}
			tmp.next = nnode
			return
		}
		i--
		tmp = tmp.next
	}
}

func (list *linkedList[E]) size() int {
	return list.len
}

func (list *linkedList[E]) isEmpty() bool {
	return list.len == 0
}

func main() {
	list := linkedList[int]{}
	println(list.isEmpty())
	list.add(1)
	list.add(2)
	list.add(3)
	list.show()
	println(list.size())
	println(list.isEmpty())

	list2 := linkedList[int]{}
	list2.add(4)
	list2.add(5)
	list2.add(6)
	list2.show()

	list.addAll(&list2)
	list.show()
	list.set(0, 10)
	list.show()

}